package com.yeziji.config.support;

import cn.hutool.core.util.StrUtil;
import com.yeziji.common.CommonEnum;
import com.yeziji.common.CommonErrorEnum;
import com.yeziji.common.CommonErrorMsg;
import com.yeziji.common.CommonResult;
import com.yeziji.constant.SystemCode;
import com.yeziji.constant.VariousStrPool;
import com.yeziji.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常处理
 *
 * @author hwy
 * @since 2023/11/29 10:33
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理 api 异常
     *
     * @param ex 要处理的异常
     * @return {@link CommonResult} 返回处理后的提示信息
     */
    @ExceptionHandler(value = ApiException.class)
    @ResponseStatus(code = HttpStatus.OK)
    public CommonResult<String> handle(ApiException ex) {
        CommonEnum errorEnum = ex.getErrorEnum();
        // 抛出普通枚举的异常
        if (errorEnum != null) {
            String commonErrorMsg = getCommonErrorMsg(errorEnum);
            // 成功信息可以通过异常进行抛出
            if (errorEnum.getCode() == SystemCode.SUCCESS.getCode()) {
                return CommonResult.success(commonErrorMsg);
            }
            // 异常信息
            if (errorEnum instanceof CommonErrorEnum) {
                return CommonResult.failed(errorEnum.getCode(), commonErrorMsg);
            }
            return CommonResult.failed(errorEnum.getCode(), commonErrorMsg);
        }
        return CommonResult.failed(getMessage(ex.getMessage()));
    }

    /**
     * 处理未知异常
     *
     * @param request 当前请求体
     * @param ex      要处理的异常
     * @return {@link CommonResult} 返回处理后的提示信息
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(code = HttpStatus.OK)
    public CommonResult<String> handlerException(HttpServletRequest request, Exception ex) {
        SystemCode error = SystemCode.ERROR;
        String method = request.getMethod();
        String requestUrl = request.getRequestURI();
        // 对于未知异常, 统一返回服务器未知错误错误码对应的错误信息
        String message = error.getDesc();
        String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
        log.error("全局异常处理===处理未知异常: code: {}, message: {}, request: {}, authorization:{}, detail: ", error.getCode(), message, method + " " + requestUrl, authorization, ex);
        return CommonResult.failed(CommonErrorMsg.SYSTEM_ERROR);
    }

    /**
     * 处理方法参数不匹配异常
     *
     * @param ex 要处理的异常
     * @return {@link CommonResult} 返回处理后的提示信息
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(code = HttpStatus.OK)
    public CommonResult<Object> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.error("MethodArgumentTypeMismatchException: {} ", ex.getMessage());
        return CommonResult.failed(CommonErrorMsg.VALIDATE_FAILED);
    }

    /**
     * 捕获 bean validate 异常
     *
     * @param ex 异常信息
     * @return {@link CommonResult} 返回处理后的提示信息
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(code = HttpStatus.OK)
    public CommonResult<Object> handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("MethodArgumentNotValidException: {} ", ex.getMessage());
        return CommonResult.validate(ex.getBindingResult());
    }

    /**
     * 捕获 bean validate 异常
     *
     * @param ex 异常信息
     * @return {@link CommonResult} 返回处理后的提示信息
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(code = HttpStatus.OK)
    public CommonResult<Object> handlerBindException(BindException ex) {
        log.error("BindException: {}", ex.getMessage());
        BindingResult bindingResult = ex.getBindingResult();
        return CommonResult.validate(bindingResult);
    }

    /**
     * 获取提示信息
     *
     * @param message 如果为 null 或者空则返回 empty
     * @return {@link String} 字符串信息
     */
    private String getMessage(String message) {
        if (StrUtil.isBlank(message)) {
            return VariousStrPool.EMPTY;
        }
        return message;
    }

    /**
     * common error msg 获取 showMsg
     *
     * @param errorEnum 异常枚举
     * @return {@link String} 枚举提示信息
     */
    public String getCommonErrorMsg(CommonEnum errorEnum) {
        if (errorEnum instanceof CommonErrorEnum) {
            return getMessage(((CommonErrorEnum) errorEnum).getShowLangMsg());
        } else {
            return getMessage(errorEnum.getLangDesc());
        }
    }
}